﻿// -------------------------------------------------------------------------
//    @FileName         :    NFServiceGM.cpp
//    @Author           :    Gao.Yi
//    @Date             :    2025-10-13
//    @Email			:    445267987@qq.com
//    @Module           :    NFServiceGM
//    @Desc             :
//
// -------------------------------------------------------------------------

#include "NFServiceGM.h"

#include "NFLogicCommon/BagPage/NFBagPageGrid.h"
#include "NFLogicCommon/BagPage/NFBagPageOp.h"
#include "NFBagPageOpMgr.h"
#include "NFPackageModule.h"
#include "NFPlayer.h"
#include "NFPlayerUtil.h"
#include "proto_cs_cmd.nanopb.h"
#include "DescStore/PlayerLevelUpDesc.h"
#include "NFLogicCommon/BagPage/NFBagDefine.h"
#include "NFLogicCommon/NFCommMacros.h"
#ifdef NF_DEBUG_MODE
#ifdef NF_STATIC_PLUGIN
#include <gtest/gtest.h>
#include "UnitTest/Bag/NFPackageServiceTest.h"
#endif
#endif

int NFServiceGM::AddLevel(NFPlayer* pPlayer, NFDataPackage& packet, const std::vector<std::string>& vecParams, std::string& info)
{
    CHECK_NULL(0, pPlayer);
    if (vecParams.size() < 1)
    {
        return -1;
    }

    int iAddLevel = NFCommon::strto<int>(vecParams[0]);
    if (iAddLevel <= 0)
    {
        LOG_ERR(pPlayer->GetRoleID(), -1, "invalid level:{}", iAddLevel);
        return -1;
    }

    uint16_t wMaxPlayerLevel = MAX_PLAYER_LEVEL;
    uint16_t wOrgLevel = pPlayer->GetLevel();
    if (wOrgLevel >= wMaxPlayerLevel)
    {
        return 0;
    }

    uint64_t ullExp = 0;
    for (int i = 1; i <= iAddLevel; i++)
    {
        int iLevel = wOrgLevel + i;
        auto pLevelUpDesc = PlayerLevelUpDesc::Instance()->GetDesc(iLevel);
        if (pLevelUpDesc)
        {
            ullExp += pLevelUpDesc->exp;
        }
    }

    NFPlayerUtil::AddExp(pPlayer, ullExp, proto_ff::EN_ICR_GM, 0);
    return 0;
}

int NFServiceGM::AddItem(NFPlayer* pPlayer, NFDataPackage& packet, const std::vector<std::string>& vecParams, std::string& info)
{
    CHECK_NULL(0, pPlayer);

    if (vecParams.size() < 2 || vecParams.size() > 3)
    {
        return -1;
    }

    uint32_t id = NFCommon::strto<uint32_t>(vecParams[0]);
    int value = NFCommon::strto<int>(vecParams[1]);
    int bind_tag = EN_BT_AUTO;
    if (vecParams.size() == 3)
    {
        bind_tag = NFCommon::strto<int>(vecParams[2]);
    }

    CHECK_EXPR(value != 0, -1, "value == 0");
    CHECK_EXPR(bind_tag >= 0 && bind_tag < 3, -1, "bind type error");

    auto pDesc = ItemDesc::Instance()->GetDesc(id);
    CHECK_NULL_WF(pPlayer->GetRoleID(), pDesc, "item desc not exist:{}", id);

    NFBagPageOpMgr opMgr(pPlayer, proto_ff::EN_ICR_GM);
    opMgr.AddAllBagPage();
    opMgr.SetBindStatForAdd((enItemBindType)bind_tag);
    if (value > 0)
    {
        int iRetCode = opMgr.AddToBag(id, value);
        CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "add item failed:{}", id);
    }
    else if (value < 0)
    {
        int iRetCode = opMgr.DelAllItems(id, -value);
        CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "del item failed:{}", id);
    }

    opMgr.Commit();

    return 0;
}

int NFServiceGM::ClearBag(NFPlayer* pPlayer, NFDataPackage& packet, const std::vector<std::string>& vecParams, std::string& info)
{
    CHECK_NULL(0, pPlayer);
    if (vecParams.size() == 0)
    {
        return ClearBagData(pPlayer, 0);
    }
    else
    {
        int iRetCode = 0;
        for (int i = 0; i < vecParams.size(); ++i)
        {
            iRetCode = ClearBagData(pPlayer, NFCommon::strto<int>(vecParams[i]));
            CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "clear bag failed");
        }
    }
    return 0;
}

int NFServiceGM::ClearBagData(NFPlayer* pPlayer, int bagType)
{
    CHECK_NULL(0, pPlayer);
    int iRetCode = 0;
    NFBagPageOpMgr opMgr(pPlayer, proto_ff::EN_ICR_GM);
    opMgr.AddAllBagPage();
    std::vector<int> vecTabIndexs;
    if (bagType == 0)
    {
        vecTabIndexs = g_personAllOpBagType;
    }
    else
    {
        vecTabIndexs.push_back(bagType);
    }

    for (int i = 0; i < vecTabIndexs.size(); ++i)
    {
        auto pOp = opMgr.GetBagPageOpByBagType(vecTabIndexs[i]);
        CHECK_NULL_WF(pPlayer->GetRoleID(), pOp, "bag page op not exist:{}", vecTabIndexs[i]);
        for (int j = 0; j < pOp->GetCapacity(); ++j)
        {
            iRetCode = pOp->DelItemByGrid(j);
            CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "clear bag failed");
        }
    }


    iRetCode = opMgr.Commit(true);
    CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "clear bag failed");
    return 0;
}

int NFServiceGM::UnitTest(NFPlayer* pPlayer, NFDataPackage& packet, const std::vector<std::string>& vecParams, std::string& info)
{
    CHECK_NULL(0, pPlayer);
#ifdef NF_DEBUG_MODE
#ifdef NF_STATIC_PLUGIN
    LOG_INFO(pPlayer->GetRoleID(), "======================================");
    LOG_INFO(pPlayer->GetRoleID(), "开始执行单元测试");
    LOG_INFO(pPlayer->GetRoleID(), "======================================");

    //清理所有背包
    ClearBagData(pPlayer, 0);

    // 运行背包服务单元测试
    NFPackageServiceTest::RunAllTests(pPlayer);

    // 运行 Google Test 所有测试
    RUN_ALL_TESTS();

    LOG_INFO(pPlayer->GetRoleID(), "======================================");
    LOG_INFO(pPlayer->GetRoleID(), "所有单元测试执行完毕");
    LOG_INFO(pPlayer->GetRoleID(), "======================================");
#endif
#else
    LOG_WARN(pPlayer->GetRoleID(), -1, "单元测试仅在 NF_DEBUG_MODE 模式下可用");
#endif
    return 0;
}

int NFServiceGM::ArrangeBag(NFPlayer* pPlayer, NFDataPackage& packet, const std::vector<std::string>& vecParams, std::string& info)
{
    CHECK_NULL(0, pPlayer);
    proto_ff::Proto_CSReq req;
    for (int i = 0; i < (int)vecParams.size(); ++i)
    {
        int bagPage = NFCommon::strto<int>(vecParams[i]);
        if (proto_ff::enBagPageType_IsValid(bagPage))
        {
            req.set_page_type((proto_ff::enBagPageType)bagPage);
            int iRetCode = FindModule<NFPackageModule>()->ProcessArrangeBagReq(packet, pPlayer->GetClientSession(), req);
            CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "arrange bag failed");
        }
    }
    return 0;
}

int NFServiceGM::PackMessage(NFPlayer* pPlayer, NFDataPackage& packet, int msgId, const proto_ff::Proto_CSReq& req)
{
    CHECK_NULL(0, pPlayer);
    NFDataPackage tempPackage = packet;
    std::string str = req.SerializeAsString();
    tempPackage.nMsgId = msgId;
    tempPackage.nMsgLen = str.size();
    tempPackage.nBuffer = (char*)str.data();
    FindModule<NFIMessageModule>()->OnHandleMessage(packet);
    return 0;
}

int NFServiceGM::SaveStorage(NFPlayer* pPlayer, NFDataPackage& packet, const std::vector<std::string>& vecParams, std::string& info)
{
    CHECK_NULL(0, pPlayer);
    if (vecParams.size() < 3)
    {
        info += "args must >= 3";
        return ERR_CODE_INVALID_REQ_PARAM;
    }

    int bagType = NFCommon::strto<int>(vecParams[0]);
    int gridIndex = NFCommon::strto<int>(vecParams[1]);
    int num = NFCommon::strto<int>(vecParams[2]);
    int itemId = 0;
    uint64_t uuid = 0;

    if (vecParams.size() >= 5)
    {
        itemId = NFCommon::strto<int>(vecParams[3]);
        uuid = NFCommon::strto<uint64_t>(vecParams[4]);
    }
    else
    {
        NFBagPageOpMgr opMgr(pPlayer, proto_ff::EN_ICR_GM, false);
        auto pOp = opMgr.GetBagPageOpByBagType(bagType);
        CHECK_NULL_WF(pPlayer->GetRoleID(), pOp, "bagType:{} not exist", bagType);
        auto pGrid = pOp->GetGrid(gridIndex);
        CHECK_NULL_WF(pPlayer->GetRoleID(), pGrid, "gridIndx:{} not exist", gridIndex);

        itemId = pGrid->GetItemID();
        uuid = pGrid->GetUUID();
    }

    proto_ff::Proto_CSReq req;
    auto pMsg = req.mutable_storage_move_pick_req();
    pMsg->set_storage_page(bagType);
    pMsg->set_grid_index(gridIndex);
    pMsg->set_item_id(itemId);
    pMsg->set_item_num(num);
    pMsg->set_uuid(uuid);

    int iRetCode = FindModule<NFPackageModule>()->ProcessSaveToStorageReq(packet, pPlayer->GetClientSession(), req);
    CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "save to storage bag failed");
    return 0;
}

int NFServiceGM::PickStorage(NFPlayer* pPlayer, NFDataPackage& packet, const std::vector<std::string>& vecParams, std::string& info)
{
    CHECK_NULL(0, pPlayer);
    if (vecParams.size() < 5)
    {
        info += "args must >= 5";
        return ERR_CODE_INVALID_REQ_PARAM;
    }

    int bagType = NFCommon::strto<int>(vecParams[0]);
    int gridIndex = NFCommon::strto<int>(vecParams[1]);
    int num = NFCommon::strto<int>(vecParams[2]);
    int itemId = NFCommon::strto<int>(vecParams[3]);
    uint64_t uuid = NFCommon::strto<uint64_t>(vecParams[4]);

    proto_ff::Proto_CSReq req;
    auto pMsg = req.mutable_storage_move_pick_req();
    pMsg->set_storage_page(bagType);
    pMsg->set_grid_index(gridIndex);
    pMsg->set_item_id(itemId);
    pMsg->set_item_num(num);
    pMsg->set_uuid(uuid);

    int iRetCode = FindModule<NFPackageModule>()->ProcessPickFromStorageReq(packet, pPlayer->GetClientSession(), req);
    CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "pick from storage bag failed");
    return 0;
}

int NFServiceGM::BuyGrid(NFPlayer* pPlayer, NFDataPackage& packet, const std::vector<std::string>& vecParams, std::string& info)
{
    CHECK_NULL(0, pPlayer);
    if (vecParams.size() < 2)
    {
        info += "args must >= 2";
        return ERR_CODE_INVALID_REQ_PARAM;
    }

    int bagType = NFCommon::strto<int>(vecParams[0]);
    int times = NFCommon::strto<int>(vecParams[1]);

    proto_ff::Proto_CSReq req;
    auto pMsg = req.mutable_buy_bag_grid_req();
    pMsg->set_page(bagType);
    pMsg->set_times(times);

    int iRetCode = FindModule<NFPackageModule>()->ProcessBuyGridReq(packet, pPlayer->GetClientSession(), req);
    CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "pick from storage bag failed");
    return 0;
}
